1 /**
2 The following example comes from
3 $(LINK http://thoughts.davisjeff.com/2010/09/25/exclusion-constraints-are-generalized-sql-unique/).
4  */
5 module test.examples_exclusion_constraint;
6 
7 version(D_Ddoc)
8 {
9     ///
10     class BlankClassSoDocsWillBeGenerated { }
11 }
12 
13 /**
14 This example is for the EXCLUSION constraint in Postgresql.
15 I will do an example with overlapping date ranges.
16 The table in SQL can be created by
17 $(D $(D $(D sql
18 CREATE TABLE b
19 (
20     id INTEGER NOT NULL PRIMARY KEY,
21     p PERIOD
22 );
23 ALTER TABLE b ADD EXCLUDE USING gist (p WITH &&);
24 
25 )))
26  */
27 unittest
28 {
29     import std.datetime;
30     
31     import db_constraints;
32 
33     struct Period
34     {
35         Date startDate;
36         Date endDate;
37 
38         invariant
39         {
40             assert(startDate <= endDate);
41         }
42 
43         bool overlapsWith(in Period i)
44         {
45             return (this.startDate <= i.endDate && i.startDate <= this.endDate);
46         }
47     }
48 
49     @ExclusionConstraint!((a, b) => a.p.overlapsWith(b.p))
50     class B
51     {
52         private int _id;
53         // marking id with not null and primary key
54         @NotNull @PrimaryKeyColumn
55         @property int id()
56         {
57             return _id;
58         }
59         @property void id(int value)
60         {
61             setter(_id, value);
62         }
63 
64         private Period _p;
65         @property inout(Period) p() inout
66         {
67             return _p;
68         }
69         @property void p(Period value)
70         {
71             setter(_p, value);
72         }
73 
74         this(int id_, Period p_)
75         {
76             this._id = id_;
77             this._p = p_;
78             // do not forget to initialize the keyed item!
79             initializeKeyedItem();
80         }
81 
82         // do not forget to add in the keyed item!
83         mixin KeyedItem!();
84     }
85 
86     alias Bs = BaseKeyedCollection!(B);
87     
88     import std.exception : assertNotThrown, assertThrown;
89 
90     auto bs = new Bs();
91 
92     auto first = Period(Date(2009, 01, 05), Date(2009, 01, 10));
93     assertNotThrown!ExclusionConstraintException(bs.add(new B(1, first))); 
94     auto second = Period(Date(2009, 01, 07), Date(2009, 01, 12));
95     assert(first.overlapsWith(second));
96     assertThrown!ExclusionConstraintException(bs.add(new B(2, second)));
97     auto third = Period(Date(2009, 01, 17), Date(2009, 01, 22));
98     assert(!first.overlapsWith(third));
99     assertNotThrown!ExclusionConstraintException(bs.add(new B(2, third)));}